package AOP;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import org.junit.jupiter.api.Test;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * User: cool
 * Date: 2019/8/10
 * Time: 17:10
 * Spring中。
 *
 * 1、如果目标对象实现了接口，默认情况下会采用JDK的动态代理实现AOP
 *
 * 2、如果目标对象实现了接口，可以强制使用CGLIB实现AOP
 *
 * 3、如果目标对象没有实现了接口，必须采用CGLIB库，spring会自动在JDK动态代理和CGLIB之间转换
 *
 * JDK动态代理只能对实现了接口的类生成代理，而不能针对类 。 CGLIB是针对类实现代理，主要是对指定的类生成一个子类，覆盖其中的方法 。 因为是继承，所以该类或方法最好不要声明成final ，final可以阻止继承和多态。
 */

public class MyTest {

    @Test
    /*
    静态代理
     */
    public void test(){
        UserDao userDao  = new UserDaoImpl();
        UserDaoProxy userDaoProxy = new UserDaoProxy(userDao);
        userDaoProxy.saveUser();
    }

    @Test
    /**
     * 动态代理1
     * 原理：是根据类加载器和接口创建代理类（此代理类是接口的实现类，所以必须使用接口 面向接口生成代理，位于java.lang.reflect包下）
     * 缺点：jdk动态代理，必须是面向接口，目标业务类必须实现接口
     */
    public void test1(){
        UserDao userDao  = new UserDaoImpl();
        UserDao  proxy = (UserDao) Proxy.newProxyInstance(UserDao.class.getClassLoader(), userDao.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("--------begin --------------");
                return method.invoke(userDao,args);
            }
        });
        proxy.saveUser();
    }
    @Test
    /**
     * 动态代理2
     */
    public void test2(){
        UserDao userDaoD = new UserDaoDImpl();
        UserDaoDProxy userDaoDProxy = new UserDaoDProxy(userDaoD);
        // 参数1：代理类的类加载器，同目标类的类加载器
        // 参数2：代理类要实现的接口列表，同目标类实现的接口列表
        // 参数3：回调，是一个InvocationHandler接口的实现对象，当调用代理对象的方法时，执行的是回调中的invoke方法
        UserDao userDaoD1 = (UserDao) Proxy.newProxyInstance(UserDaoDImpl.class.getClassLoader(),UserDaoDImpl.class.getInterfaces(),userDaoDProxy);
        userDaoD1.saveUser();
        ProxyGeneratorUtils.writeProxyClassToHardDisk("D:/$Proxy11.class",UserDaoDImpl.class);

    }
    @Test
    /**
     * cglib代理
     */
    public void test3(){
        final UserDaoCimpl userDaoCimpl = new UserDaoCimpl();
        // 创建cglib核心对象
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(userDaoCimpl.getClass());
        enhancer.setCallback(new MethodInterceptor() {
            /**
             * 当你调用目标方法时，实质上是调用该方法
             * intercept四个参数：
             * proxy:代理对象
             * method:目标方法
             * args：目标方法的形参
             * methodProxy:代理方法
             */
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("--------cglib begin --------------");
                Object invoke = method.invoke(userDaoCimpl, objects);
                System.out.println("--------cglib end --------------");
                return invoke;
            }
        });
        UserDaoCimpl userDaoCimplProxy = (UserDaoCimpl) enhancer.create();
        userDaoCimplProxy.saveUser();

    }

}
